﻿using System;
using LinearAlgebra.Vectors.Numeric;
using Real = System.Double;

namespace LinearAlgebra.Matrices
{
	public partial class Matrix
	{
		/// <summary>
		/// Returns a matrix of all zeroes
		/// </summary>
		/// <param name="n">The number of rows</param>		
		/// <param name="m">The number of columns</param>		
		/// <returns>A Matrix of Zeroes, the Zero matrix</returns>
		public static Matrix Zero( int m, int n )
		{
			Matrix A = new Matrix( m, n ); /* the matrix A */
			for( int i = 0; i < m; i++ ) { //for each row
				A[i] = new RealVector( n ); //create an array of doubles
				for( int j = 0; j < n; j++ )
					A[i][j] = 0; //assign zero to every element
			}
			return A;
		}

		/// <summary>
		/// Returns a matrix that is a function of the MatrixElementFunction{i,j} applied to each cell of the matrix
		/// </summary>		
		public static Matrix Create( int m, int n, MatrixElementFunction elementFunc )
		{
			Matrix A = new Matrix( m, n ); /* the matrix A */
			for( int i = 0; i < m; i++ )
			{
				A[i] = new RealVector(n); //create the nested array
				for( int j = 0; j < n; j++ )
					A[i][j] = elementFunc( i, j ); //initialize it using the matrix function 
			}
			return A;
		}		

		/// <summary>
		/// Prompts the user at the console to input a matrix
		/// </summary>
		/// <param name="n">Number of Rows in the Matrix</param>		
		/// <param name="m">Number of Cols in the Matrix</param>		
		public static Matrix CreateFromUserInput( int m, int n )
		{
			Matrix A = Create( n, m, delegate( int i, int j ) { 
              	//give the [start][j] slot of the matrix a random integer value between 1 and 100
              	return Real.Parse( Prompt( String.Format( "[{0}][{1}] = ", i, j ) ) );
			} );
			return A;
		}	

		/// <summary>
		/// Returns a Matrix where each ColumnCount(i == j) = 1, and each ColumnCount(i != j) = 0
		/// </summary>
		/// <param name="n">The size of the matrix; the number of elements it contains</param>		
		/// <param name="m">The size of the matrix; the number of elements it contains</param>		
		public static Matrix Identity( int m, int n )
		{
			return Create( n, m, delegate ( int i, int j ) { //the eventual resultant identity matrix               	
               	if( i == j )	//sets 1's
               		return 1;	//for the diagonal
               	return 0;		
			} );			
		}

		/// <summary>
		/// Gets a random matrix using the seed, and upper and lower boundaries specified by the arguments
		/// </summary>
		/// <param name="n">Num Rows of the Mat</param>
		/// <param name="m">Num Cols of the Mat</param>
		/// <param name="seed">The Seed provided to the random number generator</param>
		/// <param name="lower">The lower bound of the random number generator(inclusive)</param>
		/// <param name="upper">The upper bound of the random number generator(exclusive)</param>
		/// <returns>A Random Matrix</returns>
		public static Matrix Random( int m, int n, int seed, int lower, int upper )
		{			
			Random r = new Random( seed ); //we don't want the numbers to be different, this way we can test easier
			Matrix A = Create( n, m, delegate { return r.Next(lower, upper); }); //pass in a random matrix function to the GetMatrix, not sure if it will fail without the params, but it seems like it should!																				
			return A; //give the [start,j] slot of the matrix a random integer value between 1 and 100, is automatically cast as a double
		}

		/// <summary>
		/// An alias to allow for a more functional appearance in the code
		/// </summary>
		/// <param name="m">RowNum</param>
		/// <param name="n">ColNum</param>
		/// <param name="elementFunc">Function that defines the elements</param>
		/// <returns>The matrix of size MxN where each (i,j)th element is set by the matrixElementFunction</returns>
		public static Matrix WhereEach ( int m, int n, MatrixElementFunction elementFunc ) {
			return Create( m, n, elementFunc );
		}

		/// <summary>
		/// Prompt via the console for something
		/// </summary>
		/// <param name="prompt">the text to display</param>
		/// <returns>what the user types in</returns>
		private static string Prompt( string prompt ) {	//this is just for my convenience
			Console.WriteLine( prompt );				//display the prompt
			return Console.ReadLine();					//get the text and return it
		}
	}
}